//----------------------------------Include-------------------------------------
#include "mcu.h"
#include "brd_hlw8112.h"
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//HLW8112在上升沿将数据从SDO引脚输出，在下降沿从SDI引脚读取数据
//在SPI操作期间如果当两个SCLK上升沿超过9.15ms(系统时钟的2^15)时复位SPI模块(即SPI最低速率为109.25Hz)
//SCSN    ^^^^________________________________^^^^
//SCLK    ______^^^^____^^^^____^^^^____^^^^____
//SDI
//SDO
//------------------------------------------------------------------------------
//有写保护的寄存器，在向该寄存器写输入数据时要先写“写使能命令”
//
//名称          命令寄存器                   数据   描述
//读命令        {0[bit7],REG_ADR[bit6:bit0]} RDATA  从地址为REG_ADR[6:0]的寄存器中读数据，最高位是0，表示向寄存器读取数据
//写命令        {1[bit7],REG_ADR[bit6:bit0]} WDATA  向地址为REG_ADR[6:0]的寄存器中写数据，最高位是1，表示向寄存器写入数据
//写使能        0xEA                         0xE5   使能写操作
//写保护        0xEA                         0xDC   关闭写操作
//电流通道A选择 0xEA                         0x5A   电流通道A设置命令，指定当前用于计算视在功率、功率因数、
//                                                  相角、瞬时视在功率和有功功率过载的信号指示为通道A
//电流通道B选择 0xEA                         0xA5   电流通道B设置命令，指定当前用于计算视在功率、功率因数、
//                                                  相角、瞬时视在功率和有功功率过载的信号指示为通道B
//复位指令      0xEA                         0x96   复位指令，接收到指令后芯片复位
//------------------------------------------------------------------------------

//-----------------------------------Macro--------------------------------------
#define  _CS(x)        do{ mcu_spi_sw_cs(x); }while(0)
#define  _RW(x)        mcu_spi_sw_rdwr_byte(x)
#define  _NOP()        do{ for(volatile uint32_t i=0; i<10; i++) mcu_nop(); }while(0)
//如果用 nop 做延时，循环变量一定要用 volatile 声明，否则被优化掉
//------------------------------------------------------------------------------
#define  _MCLK         3579545
//------------------------------------------------------------------------------

//--------------------------------Static Func-----------------------------------
static void _wr_en(uint8_t en)
{
  _CS(0);  _NOP();
  _RW(0xEA);
  en ? _RW(0xE5) : _RW(0xDC);
  _NOP();  _CS(1);
}
//------------------------------------------------------------------------------
static void _rd_reg(uint8_t addr, uint8_t* pdata, uint8_t len)
{
  _CS(0);  _NOP();
  _RW(addr&(~0x80));
  for(uint32_t i=0; i<len; i++){
    pdata[i] = _RW(0xAA);  //dummy write
  }
  _NOP();  _CS(1);
}

static void _wr_reg(uint8_t addr, uint8_t* pdata, uint8_t len)
{
  _CS(0);  _NOP();
  _RW(addr|0x80);
  for(uint32_t i=0; i<len; i++){
    _RW(pdata[i]);
  }
  _NOP();  _CS(1);
}
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
//校表参数和计量控制寄存器  00~1D  all read and write
//计量参数和状态寄存器      20~3D  almost read only
//系统状态寄存器            43~7D  all read only

uint32_t brd_hlw8112_rd_reg(uint8_t addr, uint8_t len)
{
  assert_param( (len>=1)&&(len<=4) );
  
  uint8_t  data[4];
  _rd_reg(addr, data, len);
  switch(len){
  case 1:  return   data[0]; break;
  case 2:  return ((data[0]<<8)  +  data[1]); break;
  case 3:  return ((data[0]<<16) + (data[1]<<8)  +  data[2]); break;
  case 4:  return ((data[0]<<24) + (data[1]<<16) + (data[2]<<8) + data[3]); break;
  default: return   0;
  }
}

void brd_hlw8112_wr_reg(uint8_t addr, uint32_t para, uint8_t len)
{
  assert_param( (len>=1)&&(len<=4) );
  
  _wr_en(1);
  
  uint8_t  data[4];
  switch(len){
  case 1: data[0] = (para>> 0)&0xFF; break;
  case 2: data[0] = (para>> 8)&0xFF; data[1] = (para>> 0)&0xFF; break;
  case 3: data[0] = (para>>16)&0xFF; data[1] = (para>> 8)&0xFF; data[2] = (para>>0)&0xFF; break;
  case 4: data[0] = (para>>24)&0xFF; data[1] = (para>>16)&0xFF; data[2] = (para>>8)&0xFF; data[3] = (para>>0)&0xFF; break;
  default: break;
  }
  
  _wr_reg(addr, data, 2);
  _wr_en(0);
}
//------------------------------------------------------------------------------
uint32_t  syscon;
uint32_t  emucon;
uint32_t  emucon2;

void brd_init_hlw8112(void)
{
  uint32_t  tmp;
  
  tmp = brd_hlw8112_rd_reg(INT, 2);  //result: 0x3210, can use for test
  
//syscon
  //11--ADC3ON-U    10--ADC2ON-IB    9--ADC1ON-IA
  //8~6--PGAIB      5~3--PGAU        2~0--PGAIA
  syscon  = brd_hlw8112_rd_reg(SYSCON, 2);
  syscon  = (1<<11)|(1<<10)|(1<<9) | (0x4<<6)|(0x0<<3)|(0x4<<0);  //PGAIB=16; PGAU=1; PGAIA=16
  brd_hlw8112_wr_reg(SYSCON, syscon, 2);
  
//emucon
  //12--comp_off 比较器开启或关闭（0开1关），比较器和B通道电流测量只能二选一
  emucon  = brd_hlw8112_rd_reg(EMUCON, 2);
  emucon |= (1<<12);  //关闭比较器，使能电流测量
  brd_hlw8112_wr_reg(EMUCON, emucon, 2);
  
//emucon2
  //7-CHS_IB (1=测量IB电流，0=测量芯片内部温度)
  //6-PfactorEN, 5-WaveEn, 4-SAGEN, 3-OverEN, 2-ZxEN, 1-PeakEN, 0-VrefSel
  //获取频率必须配置 ZxEN=1,WaveEN=1
  emucon2  = brd_hlw8112_rd_reg(EMUCON2, 2);
  emucon2 |= (1<<7)|(1<<6)|(1<<5)|(1<<2);
  brd_hlw8112_wr_reg(EMUCON2, emucon2, 2);
  
  tmp = brd_hlw8112_rd_reg(EMUCON2, 2);
  while(emucon2 != tmp);
}
//------------------------------------EOF---------------------------------------









